#include "matrix.h"
#include "file.h"
#include "fileStructs.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define PARTICION 23000
#define REGPARTICION 264511500

unsigned long posicion(unsigned i, unsigned j);
int validar(unsigned i, unsigned j);
void invertir (unsigned *i, unsigned *j);
int validarNombre(const char* nombre);

void invertir (unsigned *i, unsigned *j) {
	int aux = *j;
	*j = *i;
	*i = aux;
}

unsigned long posicion(unsigned i, unsigned j) {
	unsigned long aux = (unsigned long) ( i * (i - 1) ) / 2;
	return aux + j;
}

int validar(unsigned i, unsigned j) {
	if (i == j) return -1;
	return 0;
}

int M_CREATE(const char *nombre_fisico, unsigned tamReg, unsigned maxFilCol) {
	int err;
	if (maxFilCol < 2) return RES_ERROR;
	if (maxFilCol < PARTICION)
		return R_CREATE(nombre_fisico, tamReg, posicion(maxFilCol - 1, maxFilCol - 1));

	err = R_CREATE(nombre_fisico, tamReg, REGPARTICION);

	char *nombre = (char*) malloc(strlen(nombre_fisico) + 1);

	unsigned long maxReg = posicion(maxFilCol - 1, maxFilCol - 1) - REGPARTICION;

	strcpy(nombre, nombre_fisico);
	strcat(nombre, "0");
	err = R_CREATE(nombre, tamReg, maxReg);

	free(nombre);
	return err;
}

mHandler *M_OPEN (const char* nombre_fisico, int modo) {
	mHandler *matHandler = (mHandler*) malloc(sizeof(mHandler));
	if (!matHandler) return NULL;

	if ( !(matHandler->handler[0] = R_OPEN(nombre_fisico, modo)) ) {
		free(matHandler);
		return NULL;
	}

	matHandler->regMax = matHandler->handler[0]->maxReg;
	matHandler->handler[1] = NULL;

	if (matHandler->handler[0]->maxReg == REGPARTICION) {
		char *nombre = (char*) malloc(strlen(nombre_fisico) + 1);
		strcpy(nombre, nombre_fisico);
		strcat(nombre, "0");

		matHandler->handler[1] = R_OPEN(nombre, modo);

		free(nombre);
	}

	if (matHandler->handler[1])
		matHandler->regMax += matHandler->handler[1]->maxReg;

	return matHandler;
}

int M_CLOSE (mHandler *handler) {
	if (!handler) return RES_ERROR;

	R_CLOSE(handler->handler[0]);

	if (handler->handler[1])
		R_CLOSE(handler->handler[1]);

	free(handler);

	return RES_OK;
}

int M_READ (mHandler *handler, unsigned posFil, unsigned posCol, void* reg) {
	if (!handler) return RES_ERROR;
	if (validar(posFil,posCol)) return RES_ERROR;
	if (posFil < posCol) invertir(&posFil, &posCol);
	unsigned long pos = posicion(posFil, posCol);
	if (pos <= handler->regMax) {
		if (pos < REGPARTICION)
			return R_READ(handler->handler[0], pos, reg);

		return R_READ(handler->handler[1], pos - REGPARTICION, reg);
	}
	return RES_ERROR;
}

bool M_EXISTE_REG (mHandler *handler, unsigned posFil, unsigned posCol ) {
	if (!handler) return RES_ERROR;
	if (validar(posFil,posCol)) return RES_ERROR;
	if (posFil < posCol) invertir(&posFil, &posCol);
	unsigned long pos = posicion(posFil, posCol);
	if (pos <= handler->regMax) {
		if (pos < REGPARTICION)
			return R_EXISTE_REG(handler->handler[0], pos);

		return R_EXISTE_REG(handler->handler[1], pos - REGPARTICION);
	}
	return RES_ERROR;
}

int M_WRITE (mHandler *handler, unsigned posFil, unsigned posCol, const void* reg) {
	if (!handler) return RES_ERROR;
	if (validar(posFil,posCol)) return RES_ERROR;
	if (posFil < posCol) invertir(&posFil, &posCol);
	unsigned long pos = posicion(posFil, posCol);
	if (pos <= handler->regMax) {
		if (pos < REGPARTICION)
			return R_WRITE(handler->handler[0], pos, reg);

		return R_WRITE(handler->handler[1], pos - REGPARTICION, reg);
	}
	return RES_ERROR;
}

int M_UPDATE (mHandler *handler, unsigned posFil, unsigned posCol, const void* reg) {
	if (!handler) return RES_ERROR;
	if (validar(posFil,posCol)) return RES_ERROR;
	if (posFil < posCol) invertir(&posFil, &posCol);
	unsigned long pos = posicion(posFil, posCol);
	if (pos <= handler->regMax) {
		if (pos < REGPARTICION)
			return R_UPDATE(handler->handler[0], pos, reg);

		return R_UPDATE(handler->handler[1], pos - REGPARTICION, reg);
	}
	return RES_ERROR;
}

int M_DELETE (mHandler *handler, unsigned posFil, unsigned posCol) {
	if (!handler) return RES_ERROR;
	if (validar(posFil,posCol)) return RES_ERROR;
	if (posFil < posCol) invertir(&posFil, &posCol);
	unsigned long pos = posicion(posFil, posCol);
	if (pos <= handler->regMax) {
		if (pos < REGPARTICION)
			return R_DELETE(handler->handler[0], pos);

		return R_DELETE(handler->handler[1], pos - REGPARTICION);
	}
	return RES_ERROR;
}

int M_DESTROY(const char* nombre_fisico) {

	int err = R_DESTROY(nombre_fisico);

	char *nombre = (char*) malloc(strlen(nombre_fisico) + 1);
	strcpy(nombre, nombre_fisico);
	strcat(nombre, "0");
	R_DESTROY(nombre);

	return err;
}
